#!/usr/bin/env python
# $Id: dict.py df54dec975f4 2012/09/09 20:22:40 pgurumur $
# Copyright (c) 2009 Prabhu Gurumurthy  <pgurumur@gmail.com>
# 
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

# Python imports
import warnings
import optparse
import signal
import sys

# Local imports
from venya.lib import cmdparser
from venya.lib import client

__version__ = "$Revision: df54dec975f4 $"
__author__ = "$Author: pgurumur $"

class DictCmdLine(cmdparser.GetOpt):
   """
   Subclass of GetOpt class from cmdparser
   1. init for this class, just calls super
   2. dictClient function is being called from handle() function
   3. handle is the starting point for this class

   Dictionary client implemented here will work in any of the two ways
   a. Default method is to present a command line with tab completion
      to issue commands and retrieve information for the words from the
      dictionary server
   b. Just present the word as an option using -w switch, will retrieve
      information for just that one word and exit
   """

   ###
   """
   Option list meta data, expands the default meta deta from GetOpt
   -w | --word switch specify just one word to retrieve information for
   -p | --port switch to use for port apart from default which is 2628
   """
   option_list = cmdparser.GetOpt.option_list + (
         optparse.make_option("-w", "--word", help = "Word to lookup",
            dest = "word"),
         optparse.make_option("-p", "--port", type = "int",
            help = "Dictionary client port to use, default: 2628",
            default = 2628, dest = "port"),
   )

   help = """
   Dictionary client based on RFC 2229, uses TCP as transport protocol and
   port 2628, pure python implemention with tab completion for the command
   line
   """

   def __init__(self, **Keywords):
      """
      @brief init function that just calls super to instantiate the object
      @param self 'this' pointer for the class
      @param Keywords functional parameter for the class
      @return returns the object (subclass of GetOpt class)
      """
      super(DictCmdLine, self).__init__(**Keywords)

   def handle(self):
      """
      @brief parse the command line and call dictClietn function
      @param self 'this' pointer for the class
      @return None, void function
      """

      # Parse the command line, the host value is not specified in args[1]
      # then IndexError is raised, otherwise dictClient is called with 
      # Options and host
      (options, args) = self.parse()
      try:
         host = args[1]
      except IndexError, message:
         self.error("no hostname defined!")
      else:
         self.dictClient(options, host)

   def dictClient(self, Options, Host):
      """
      @brief function that either spanws the shell to the dictionary server
             using a command line or to retrieve information from the
             dictionary server based on -w switch
      @param self 'this' pointer for the class
      @param Options container with the values for the command line switches
      @param Host dictionary server (IP address or dns name)
      """
      port = 0
      # If port value is provied which is by default (2628), verify that
      # value to be integer
      if Options.port:
         try:
            port = int(Options.port)
         except ValueError, message:
            self.error(message)

      # If -w | --word switch is invoked, then definition for the word  will be
      # retrieved from the dictionary server
      # Otherwise, else loop is followed to create a command line shell
      if Options.word:
         try:
            print client.GetWord(Host, port, Options.word)
         except client.DictError, message:
            self.error(message)
      else:
         # Try instantiating the dictionary client using Host and port
         # variables
         try:
            dictClient = client.DictClient(Host, port)
         except client.DictError, message:
            self.error(message)
         except KeyboardInterrupt:
            self.error("interrupted from keyboard!")

         # Setup signal handles, so that with keyboard signal the code can exit
         # gracefully
         signal.signal(signal.SIGTERM, dictClient.Signal)
         signal.signal(signal.SIGINT, dictClient.Signal)
         signal.signal(signal.SIGHUP, dictClient.Signal)
         signal.signal(signal.SIGPIPE, dictClient.Signal)

         # Spawn the shell, shell by default will have command line tab
         # completion
         try:
            dictClient.Input()
         except client.DictError, message:
            self.error(message)

         # Once done, close the dictionary client
         dictClient.Close()

# If the namespace is main
if __name__ == "__main__":
   # Constuct the dictionary client command line option
   dictopt = DictCmdLine(version = 1.2, usage = "host", args = sys.argv)

   # If we have too few parameters, then print help and exit
   if len(dictopt) <= 1:
      dictopt.printhelp()
   else:
      # If we have right number of arguments, call the default handler the
      # handle() function, any errors will be GetOptError. The errors reported
      # are printed to the command line and program exits with code 1
      try:
         dictopt.handle()
      except cmdparser.GetOptError, message:
         print message
         sys.exit(1)
